<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>7×8拼图游戏</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
    
    <!-- Tailwind 配置 -->
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#3B82F6',
                        secondary: '#10B981',
                        accent: '#F59E0B',
                        dark: '#1E293B',
                        light: '#F8FAFC',
                        error: '#EF4444',
                        hint: '#8B5CF6'
                    },
                    fontFamily: {
                        inter: ['Inter', 'system-ui', 'sans-serif'],
                    },
                }
            }
        }
    </script>
    
    <style type="text/tailwindcss">
        @layer utilities {
            .content-auto { content-visibility: auto; }
            .puzzle-shadow { box-shadow: 0 4px 6px -1px rgba(0,0,0,0.2), 0 2px 4px -1px rgba(0,0,0,0.1); }
            .puzzle-hover { transition: transform 0.2s, box-shadow 0.2s; }
            .puzzle-hover:hover, .puzzle-hover:active { transform: translateY(-2px); box-shadow: 0 10px 15px -3px rgba(0,0,0,0.3), 0 4px 6px -2px rgba(0,0,0,0.1); }
            .drop-highlight { background-color: rgba(59,130,246,0.1); border: 2px dashed #3B82F6; }
            .completed-animation { animation: pulse 1s ease-in-out; }
            .correct-piece { 
                border: 2px solid #10B981 !important;
                box-shadow: 0 0 0 2px rgba(16, 185, 129, 0.3) !important;
                outline: none !important;
            }
            .incorrect-piece { 
                border: 2px solid #EF4444 !important;
                animation: shake 0.5s ease-in-out;
                box-shadow: 0 0 0 2px rgba(239, 68, 68, 0.3) !important;
                outline: none !important;
            }
            .dragging-ghost { opacity: 0.9; transform: scale(1.1); position: absolute; pointer-events: none; z-index: 100; }
            .snap-align { transition: transform 0.1s ease-out; }
            .piece-hidden { visibility: hidden; }
            .thumbnail-container { 
                position: relative; 
                overflow: hidden; 
                border-radius: 0.5rem; 
                margin: 0 auto; 
                display: flex; 
                justify-content: center; 
                align-items: center; 
                max-width: 100%;
            }
            .thumbnail-overlay { 
                position: absolute; 
                bottom: 0; 
                left: 0; 
                right: 0; 
                padding: 0.375rem;
                background: rgba(0,0,0,0.7);
                color: white; 
                font-size: 0.75rem;
                text-align: center; 
            }
            .loading-state { 
                padding: 1.5rem; 
                color: #6b7280;
                min-height: 200px;
            }
            .loading-state:not(.hidden) {
                display: flex;
                justify-content: center;
                align-items: center;
            }
            .hint-bubble {
                position: absolute;
                background: rgba(139, 92, 246, 0.95);
                color: white;
                padding: 0.375rem 0.75rem;
                border-radius: 0.5rem;
                box-shadow: 0 4px 12px rgba(139, 92, 246, 0.4);
                z-index: 50;
                animation: hintFadeIn 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
                max-width: 200px;
                font-size: 0.8rem;
            }
            .hint-bubble:after {
                content: '';
                position: absolute;
                top: 100%;
                left: 16px;
                border-width: 6px 6px 0;
                border-style: solid;
                border-color: rgba(139, 92, 246, 0.95) transparent;
            }
            .hint-highlight {
                animation: hintPulse 1.5s infinite;
                border: 2px dashed #8B5CF6 !important;
                background-color: rgba(139, 92, 246, 0.1);
            }
            /* 触摸反馈样式 */
            .touch-active {
                transform: scale(0.95);
                transition: transform 0.1s ease;
            }
            /* 拼图区域横向滚动容器 */
            .puzzle-scroll-container {
                overflow-x: auto;
                padding-bottom: 0.75rem;
                -webkit-overflow-scrolling: touch;
            }
            @keyframes pulse { 0%,100% { transform: scale(1); } 50% { transform: scale(1.03); } }
            @keyframes shake { 0%, 100% { transform: translateX(0); } 20%, 60% { transform: translateX(-3px); } 40%, 80% { transform: translateX(3px); } }
            @keyframes hintFadeIn { 
                from { opacity: 0; transform: translateY(-8px) scale(0.95); } 
                to { opacity: 1; transform: translateY(0) scale(1); } 
            }
            @keyframes hintPulse { 
                0%, 100% { border-color: rgba(139, 92, 246, 0.6); background-color: rgba(139, 92, 246, 0.05); } 
                50% { border-color: rgba(139, 92, 246, 1); background-color: rgba(139, 92, 246, 0.15); } 
            }
        }
    </style>
</head>
<body class="font-inter bg-gradient-to-br from-light to-gray-100 min-h-screen text-dark pb-12">
    <!-- 顶部导航栏 -->
    <header class="bg-white shadow-md sticky top-0 z-50 transition-all duration-300">
        <div class="container mx-auto px-3 py-2 flex justify-between items-center">
            <div class="flex items-center space-x-2">
                <i class="fa fa-puzzle-piece text-primary text-xl"></i>
                <h1 class="text-lg md:text-xl font-bold text-dark">7×8拼图</h1>
            </div>
            <div class="flex items-center space-x-2">
                <button id="reset-btn" class="flex items-center space-x-1 bg-gray-200 hover:bg-gray-300 px-2 py-1 rounded-md transition-colors">
                    <i class="fa fa-refresh"></i>
                    <span class="text-sm">重置</span>
                </button>
                <button id="help-btn" class="flex items-center space-x-1 bg-gray-200 hover:bg-gray-300 px-2 py-1 rounded-md transition-colors">
                    <i class="fa fa-question-circle"></i>
                    <span class="text-sm">帮助</span>
                </button>
            </div>
        </div>
    </header>

    <!-- 主内容区 -->
    <main class="container mx-auto px-3 py-4">
        <!-- 游戏状态信息 -->
        <div class="flex flex-col md:flex-row justify-between items-center mb-4 gap-3">
            <div class="flex flex-wrap gap-2 justify-center">
                <div class="bg-white rounded-lg shadow p-2 flex items-center">
                    <i class="fa fa-clock-o text-accent mr-1.5 text-sm"></i>
                    <span class="text-sm">时间: <span id="timer" class="font-semibold">00:00</span></span>
                </div>
                <div class="bg-white rounded-lg shadow p-2 flex items-center">
                    <i class="fa fa-exchange text-primary mr-1.5 text-sm"></i>
                    <span class="text-sm">移动: <span id="moves" class="font-semibold">0</span></span>
                </div>
                <div class="bg-white rounded-lg shadow p-2 flex items-center">
                    <i class="fa fa-check-square-o text-secondary mr-1.5 text-sm"></i>
                    <span class="text-sm">完成: <span id="completed" class="font-semibold">0</span>/56</span>
                </div>
            </div>
            
            <!-- 图片上传区域 -->
            <div class="w-full md:w-auto">
                <label for="image-upload" class="flex items-center justify-center gap-1.5 bg-primary hover:bg-primary/90 text-white px-3 py-1.5 rounded-md transition-colors cursor-pointer w-full md:w-auto text-sm">
                    <i class="fa fa-upload"></i>
                    <span>上传图片</span>
                    <input id="image-upload" type="file" accept="image/*" class="hidden">
                </label>
            </div>
        </div>
        
        <!-- 拼图区域 -->
        <div class="bg-white rounded-xl shadow-lg p-3 md:p-5 mb-4 relative">
            <h2 class="text-base md:text-lg font-semibold mb-3 flex items-center">
                <i class="fa fa-th text-primary mr-2"></i>拼图区域
            </h2>
            
            <!-- 居中缩略图参考区域 -->
            <div class="mb-3 flex justify-center">
                <div id="thumbnail-container" class="thumbnail-container hidden max-w-full">
                    <img id="reference-thumbnail" src="" alt="完整图片参考" class="max-w-full h-auto puzzle-shadow rounded-md">
                    <div class="thumbnail-overlay">
                        <i class="fa fa-info-circle mr-1"></i> 完整图片参考
                    </div>
                </div>
            </div>
            
            <!-- 加载状态 -->
            <div id="loading-state" class="loading-state">
                <div class="flex flex-col items-center">
                    <div class="w-8 h-8 border-2 border-primary border-t-transparent rounded-full animate-spin mb-2"></div>
                    <span>初始图片加载中...</span>
                </div>
            </div>
            
            <!-- 拼图容器 -->
            <div class="puzzle-scroll-container">
                <div id="puzzle-container" class="grid grid-cols-7 gap-1 relative overflow-hidden bg-gray-100 rounded-lg hidden">
                    <!-- 拼图格子动态生成 -->
                </div>
            </div>
        </div>
        
        <!-- 拼图块池 -->
        <div class="bg-white rounded-xl shadow-lg p-3 md:p-5">
            <h2 class="text-base md:text-lg font-semibold mb-3 flex items-center">
                <i class="fa fa-cubes text-accent mr-2"></i>拼图块池
            </h2>
            <div id="pieces-container" class="grid grid-cols-4 sm:grid-cols-6 md:grid-cols-8 gap-2 sm:gap-3">
                <!-- 拼图块动态生成 -->
            </div>
        </div>
    </main>
    
    <!-- 完成提示模态框 -->
    <div id="completion-modal" class="fixed inset-0 bg-black/50 flex items-center justify-center z-50 hidden">
        <div class="bg-white rounded-xl p-5 max-w-md w-full mx-4 transform transition-all">
            <div class="text-center">
                <div class="inline-flex items-center justify-center w-14 h-14 rounded-full bg-secondary/20 text-secondary mb-3">
                    <i class="fa fa-trophy text-2xl"></i>
                </div>
                <h2 class="text-xl font-bold mb-2">恭喜完成!</h2>
                <p class="text-gray-600 mb-4 text-sm">你成功完成了这个7×8的拼图挑战</p>
                <div class="grid grid-cols-2 gap-3 mb-5">
                    <div class="bg-gray-100 rounded-lg p-2">
                        <p class="text-xs text-gray-500">用时</p>
                        <p id="final-time" class="text-lg font-bold text-primary">00:00</p>
                    </div>
                    <div class="bg-gray-100 rounded-lg p-2">
                        <p class="text-xs text-gray-500">移动次数</p>
                        <p id="final-moves" class="text-lg font-bold text-accent">0</p>
                    </div>
                </div>
                <button id="play-again-btn" class="bg-primary hover:bg-primary/90 text-white px-5 py-2 rounded-md transition-colors w-full">
                    再玩一次
                </button>
            </div>
        </div>
    </div>
    
    <!-- 帮助模态框 -->
    <div id="help-modal" class="fixed inset-0 bg-black/50 flex items-center justify-center z-50 hidden">
        <div class="bg-white rounded-xl p-5 max-w-md w-full mx-4 max-h-[80vh] overflow-y-auto">
            <div class="flex justify-between items-center mb-3">
                <h2 class="text-lg font-bold">游戏帮助</h2>
                <button id="close-help-btn" class="text-gray-500 hover:text-gray-700">
                    <i class="fa fa-times text-lg"></i>
                </button>
            </div>
            <div class="space-y-3 text-sm">
                <div>
                    <h3 class="font-semibold text-primary">游戏玩法</h3>
                    <p>1. 从下方拼图块池中拖动拼图块，放置到上方对应的拼图格子中；</p>
                    <p>2. 正确放置时，拼图块会显示绿色边框；</p>
                    <p>3. 错误放置时，拼图块会显示红色边框并轻微抖动；</p>
                    <p>4. 将拼图块拖到已有错误拼图块的位置时，两个拼图块会交换位置；</p>
                    <p>5. 全部56块拼图放置正确后，游戏完成。</p>
                </div>
                <div>
                    <h3 class="font-semibold text-primary">手机操作</h3>
                    <p>• 长按拼图块并拖动到目标位置</p>
                    <p>• 拼图区域可左右滑动查看完整拼图</p>
                </div>
            </div>
        </div>
    </div>

    <script>
        // 游戏配置与状态
        const DEFAULT_PUZZLE_IMAGE = "https://cbu01.alicdn.com/img/ibank/2016/523/201/3397102325_717789860.jpg";
        const ROWS = 7;
        const COLS = 8;
        const TOTAL_PIECES = ROWS * COLS;
        const SNAP_DISTANCE = 30;
        const MAX_THUMBNAIL_HEIGHT = 160;
        const MAX_PIECE_ERRORS = 2;
        const MIN_PIECE_SIZE = 30;
        
        let gameState = {
            image: null,
            pieces: [],
            solution: [],
            moves: 0,
            completedPieces: 0,
            pieceErrors: {},
            currentPieceId: null,
            startTime: null,
            timerInterval: null,
            elapsedTime: 0,
            draggedPiece: null,
            ghostPiece: null,
            pieceSize: 0,
            offsetX: 0,
            offsetY: 0,
            currentDropZone: null,
            isDragging: false,
            activeHint: null,
            activeHintPosition: null,
            touchStartX: 0,
            touchStartY: 0,
            isSwapping: false, // 交换状态
            draggedPieceOriginalParent: null, // 记录拖拽前的父容器
            isNewMove: false // 标记是否为新的移动操作
        };

        // DOM 元素获取
        const dom = {
            puzzleContainer: document.getElementById('puzzle-container'),
            piecesContainer: document.getElementById('pieces-container'),
            imageUpload: document.getElementById('image-upload'),
            resetBtn: document.getElementById('reset-btn'),
            helpBtn: document.getElementById('help-btn'),
            helpModal: document.getElementById('help-modal'),
            closeHelpBtn: document.getElementById('close-help-btn'),
            completionModal: document.getElementById('completion-modal'),
            playAgainBtn: document.getElementById('play-again-btn'),
            timer: document.getElementById('timer'),
            moves: document.getElementById('moves'),
            completed: document.getElementById('completed'),
            finalTime: document.getElementById('final-time'),
            finalMoves: document.getElementById('final-moves'),
            thumbnailContainer: document.getElementById('thumbnail-container'),
            referenceThumbnail: document.getElementById('reference-thumbnail'),
            loadingState: document.getElementById('loading-state')
        };

        // 初始化事件监听
        function initEventListeners() {
            // 鼠标事件
            document.addEventListener('mousemove', handleMouseMove);
            document.addEventListener('mouseup', handleMouseUp);
            document.addEventListener('mouseleave', handleMouseLeave);
            
            // 触摸事件
            document.addEventListener('touchmove', handleTouchMove, { passive: false });
            document.addEventListener('touchend', handleTouchEnd);
            document.addEventListener('touchcancel', handleTouchCancel);
            
            // 其他事件
            dom.imageUpload.addEventListener('change', handleImageUpload);
            dom.resetBtn.addEventListener('click', resetGame);
            dom.helpBtn.addEventListener('click', () => dom.helpModal.classList.remove('hidden'));
            dom.closeHelpBtn.addEventListener('click', () => dom.helpModal.classList.add('hidden'));
            dom.playAgainBtn.addEventListener('click', () => {
                dom.completionModal.classList.add('hidden');
                resetGame();
            });
            dom.helpModal.addEventListener('click', (e) => e.target === dom.helpModal && dom.helpModal.classList.add('hidden'));
            dom.completionModal.addEventListener('click', (e) => e.target === dom.completionModal && dom.completionModal.classList.add('hidden'));
        }

        // 显示提示气泡
        function showHint(message, positionElement) {
            clearActiveHint();
            
            const rect = positionElement.getBoundingClientRect();
            let x = rect.left - 15;
            let y = rect.top - 50;
            
            // 确保提示框在屏幕内
            if (x < 10) x = rect.right - 10;
            if (y < 10) y = rect.bottom + 10;
            
            const hint = document.createElement('div');
            hint.className = 'hint-bubble';
            hint.innerHTML = `<i class="fa fa-lightbulb-o mr-1"></i> ${message}`;
            hint.style.left = `${x}px`;
            hint.style.top = `${y}px`;
            
            document.body.appendChild(hint);
            gameState.activeHint = hint;
            positionElement.classList.add('hint-highlight');
            gameState.activeHintPosition = positionElement;
            
            setTimeout(clearActiveHint, 3000);
        }

        // 清除当前提示
        function clearActiveHint() {
            if (gameState.activeHint) {
                gameState.activeHint.style.opacity = '0';
                setTimeout(() => gameState.activeHint.remove(), 300);
                gameState.activeHint = null;
            }
            
            if (gameState.activeHintPosition) {
                gameState.activeHintPosition.classList.remove('hint-highlight');
                gameState.activeHintPosition = null;
            }
        }

        // 加载默认图片
        function loadDefaultImage() {
            const img = new Image();
            img.onload = function() {
                gameState.image = img;
                updateThumbnail(img);
                startNewGame();
                dom.loadingState.classList.add('hidden');
                dom.puzzleContainer.classList.remove('hidden');
                dom.thumbnailContainer.classList.remove('hidden');
            };
            img.onerror = function() {
                dom.loadingState.innerHTML = `
                    <div class="flex flex-col items-center text-red-500">
                        <i class="fa fa-exclamation-circle text-xl mb-2"></i>
                        <span>默认图片加载失败，请手动上传图片</span>
                    </div>
                `;
            };
            img.src = DEFAULT_PUZZLE_IMAGE;
        }

        // 处理图片上传
        function handleImageUpload(e) {
            const file = e.target.files[0];
            if (!file) return;

            const reader = new FileReader();
            reader.onload = function(event) {
                const img = new Image();
                img.onload = function() {
                    gameState.image = img;
                    updateThumbnail(img);
                    startNewGame();
                    dom.loadingState.classList.add('hidden');
                    dom.puzzleContainer.classList.remove('hidden');
                    dom.thumbnailContainer.classList.remove('hidden');
                };
                img.src = event.target.result;
            };
            reader.readAsDataURL(file);
        }

        // 更新缩略图
        function updateThumbnail(image) {
            dom.referenceThumbnail.src = image.src;
            dom.referenceThumbnail.alt = "完整图片参考";

            let newWidth, newHeight;
            if (image.height > MAX_THUMBNAIL_HEIGHT) {
                const ratio = MAX_THUMBNAIL_HEIGHT / image.height;
                newHeight = MAX_THUMBNAIL_HEIGHT;
                newWidth = image.width * ratio;
            } else {
                newWidth = image.width;
                newHeight = image.height;
            }

            dom.referenceThumbnail.style.maxWidth = `${newWidth}px`;
            dom.referenceThumbnail.style.maxHeight = `${newHeight}px`;
        }

        // 开始新游戏
        function startNewGame() {
            // 强制清空拼图容器和拼图块池
            dom.puzzleContainer.innerHTML = '';
            dom.piecesContainer.innerHTML = '';
            
            resetGameState();
            createPuzzlePieces();
            renderPuzzlePositions();
            renderPuzzlePieces();
            startTimer();
        }

        // 重置游戏状态
        function resetGameState() {
            clearActiveHint();
            
            gameState.pieces = [];
            gameState.solution = [];
            gameState.moves = 0;
            gameState.completedPieces = 0;
            gameState.pieceErrors = {};
            gameState.currentPieceId = null;
            gameState.elapsedTime = 0;
            gameState.draggedPiece = null;
            gameState.isSwapping = false;
            gameState.draggedPieceOriginalParent = null;
            gameState.isNewMove = false;
            
            if (gameState.ghostPiece) {
                gameState.ghostPiece.remove();
                gameState.ghostPiece = null;
            }
            
            if (gameState.timerInterval) {
                clearInterval(gameState.timerInterval);
                gameState.timerInterval = null;
            }
            
            dom.moves.textContent = '0';
            dom.completed.textContent = '0';
            dom.timer.textContent = '00:00';
        }

        // 创建拼图块
        function createPuzzlePieces() {
            // 计算屏幕可用宽度（减去边距）
            const screenWidth = window.innerWidth - 30;
            
            // 计算适合手机屏幕的拼图块尺寸
            const calculatedSize = Math.floor(screenWidth / COLS);
            
            // 基于图片比例的最大可能尺寸
            const imageBasedSize = Math.min(
                Math.floor(gameState.image.width / COLS),
                Math.floor(gameState.image.height / ROWS)
            );
            
            // 确定最终拼图块尺寸，不小于最小尺寸
            gameState.pieceSize = Math.max(MIN_PIECE_SIZE, Math.min(calculatedSize, imageBasedSize));
            
            // 生成拼图块数据
            for (let row = 0; row < ROWS; row++) {
                for (let col = 0; col < COLS; col++) {
                    const index = row * COLS + col;
                    const pieceId = `piece-${index}`;
                    
                    gameState.solution.push(index);
                    gameState.pieceErrors[pieceId] = 0;
                    
                    gameState.pieces.push({
                        id: pieceId,
                        index: index,
                        row: row,
                        col: col,
                        size: gameState.pieceSize,
                        x: -col * gameState.pieceSize,
                        y: -row * gameState.pieceSize,
                        placed: false,
                        correctPosition: {row, col},
                        isCorrect: false // 跟踪该拼图是否已正确放置
                    });
                }
            }
            
            shuffleArray(gameState.pieces);
        }

        // 渲染拼图位置（空白格子）
        function renderPuzzlePositions() {
            dom.puzzleContainer.innerHTML = '';
            
            // 设置拼图容器样式
            dom.puzzleContainer.style.gridTemplateColumns = `repeat(${COLS}, ${gameState.pieceSize}px)`;
            dom.puzzleContainer.style.width = `${gameState.pieceSize * COLS + 28}px`;
            dom.puzzleContainer.style.margin = '0 auto';
            
            // 获取容器位置
            const containerRect = dom.puzzleContainer.getBoundingClientRect();
            
            // 创建拼图位置
            for (let row = 0; row < ROWS; row++) {
                for (let col = 0; col < COLS; col++) {
                    const index = row * COLS + col;
                    const position = document.createElement('div');
                    position.id = `position-${index}`;
                    position.className = 'border border-gray-200 bg-gray-50 aspect-square flex items-center justify-center relative';
                    position.dataset.index = index;
                    position.dataset.row = row;
                    position.dataset.col = col;
                    position.dataset.x = containerRect.left + col * gameState.pieceSize;
                    position.dataset.y = containerRect.top + row * gameState.pieceSize;
                    
                    dom.puzzleContainer.appendChild(position);
                }
            }
        }

        // 渲染拼图块
        function renderPuzzlePieces() {
            dom.piecesContainer.innerHTML = '';
            
            gameState.pieces.forEach(piece => {
                if (!piece.placed) {
                    const pieceElement = document.createElement('div');
                    pieceElement.id = piece.id;
                    pieceElement.className = 'puzzle-shadow puzzle-hover cursor-grab active:cursor-grabbing aspect-square rounded-md overflow-hidden';
                    pieceElement.style.width = `${piece.size}px`;
                    pieceElement.style.height = `${piece.size}px`;
                    pieceElement.style.backgroundImage = `url(${gameState.image.src})`;
                    pieceElement.style.backgroundPosition = `${piece.x}px ${piece.y}px`;
                    pieceElement.style.backgroundSize = `${piece.size * COLS}px ${piece.size * ROWS}px`;
                    pieceElement.dataset.index = piece.index;
                    pieceElement.dataset.correctRow = piece.correctPosition.row;
                    pieceElement.dataset.correctCol = piece.correctPosition.col;
                    
                    // 添加鼠标和触摸事件监听
                    pieceElement.addEventListener('mousedown', handleMouseDown);
                    pieceElement.addEventListener('touchstart', handleTouchStart, { passive: false });
                    
                    dom.piecesContainer.appendChild(pieceElement);
                }
            });
        }

        // 创建幽灵拖拽块
        function createGhostPiece(pieceElement) {
            const ghost = pieceElement.cloneNode(true);
            ghost.id = `ghost-${pieceElement.id}`;
            ghost.className = 'dragging-ghost puzzle-shadow';
            
            const rect = pieceElement.getBoundingClientRect();
            ghost.style.width = `${rect.width}px`;
            ghost.style.height = `${rect.height}px`;
            ghost.style.left = `${rect.left}px`;
            ghost.style.top = `${rect.top}px`;
            
            document.body.appendChild(ghost);
            return ghost;
        }

        // 鼠标按下事件
        function handleMouseDown(e) {
            if (e.button !== 0 || gameState.isSwapping) return; // 交换中不允许新的拖拽
            
            clearActiveHint();
            
            gameState.draggedPiece = this;
            gameState.currentPieceId = this.id;
            // 记录拖拽前的父容器（原始位置）
            gameState.draggedPieceOriginalParent = this.parentElement;
            
            const rect = this.getBoundingClientRect();
            gameState.offsetX = e.clientX - rect.left;
            gameState.offsetY = e.clientY - rect.top;
            
            gameState.ghostPiece = createGhostPiece(this);
            this.classList.add('piece-hidden');
            gameState.isDragging = true;
            gameState.isNewMove = false; // 初始化新移动标记
            
            e.preventDefault();
            e.stopPropagation();
        }

        // 触摸开始事件
        function handleTouchStart(e) {
            // 防止多点触摸和交换中操作
            if (e.touches.length !== 1 || gameState.isSwapping) return;
            
            clearActiveHint();
            
            gameState.draggedPiece = this;
            gameState.currentPieceId = this.id;
            // 记录拖拽前的父容器（原始位置）
            gameState.draggedPieceOriginalParent = this.parentElement;
            
            const rect = this.getBoundingClientRect();
            const touch = e.touches[0];
            
            // 记录触摸起始位置和偏移量
            gameState.offsetX = touch.clientX - rect.left;
            gameState.offsetY = touch.clientY - rect.top;
            gameState.touchStartX = touch.clientX;
            gameState.touchStartY = touch.clientY;
            
            // 添加触摸反馈
            this.classList.add('touch-active');
            
            // 创建幽灵拖拽块
            gameState.ghostPiece = createGhostPiece(this);
            this.classList.add('piece-hidden');
            gameState.isDragging = true;
            gameState.isNewMove = false; // 初始化新移动标记
            
            e.preventDefault();
            e.stopPropagation();
        }

        // 鼠标移动事件
        function handleMouseMove(e) {
            if (!gameState.isDragging || !gameState.ghostPiece || gameState.isSwapping) return;
            
            let x = e.clientX - gameState.offsetX;
            let y = e.clientY - gameState.offsetY;
            
            updateCurrentDropZone(e.clientX, e.clientY);
            updateGhostPosition(x, y);
            
            e.preventDefault();
        }

        // 触摸移动事件
        function handleTouchMove(e) {
            if (!gameState.isDragging || !gameState.ghostPiece || e.touches.length !== 1 || gameState.isSwapping) return;
            
            const touch = e.touches[0];
            let x = touch.clientX - gameState.offsetX;
            let y = touch.clientY - gameState.offsetY;
            
            updateCurrentDropZone(touch.clientX, touch.clientY);
            updateGhostPosition(x, y);
            
            e.preventDefault();
        }

        // 更新幽灵块位置
        function updateGhostPosition(x, y) {
            let snapped = false;
            if (gameState.currentDropZone) {
                const dropX = parseInt(gameState.currentDropZone.dataset.x);
                const dropY = parseInt(gameState.currentDropZone.dataset.y);
                const distance = Math.hypot(x - dropX, y - dropY);
                
                if (distance < SNAP_DISTANCE) {
                    x = dropX;
                    y = dropY;
                    gameState.ghostPiece.classList.add('snap-align');
                    snapped = true;
                }
            }
            
            gameState.ghostPiece.style.left = `${x}px`;
            gameState.ghostPiece.style.top = `${y}px`;
            
            if (!snapped) {
                gameState.ghostPiece.classList.remove('snap-align');
            }
        }

        // 鼠标释放事件
        function handleMouseUp(e) {
            if (!gameState.isDragging || !gameState.draggedPiece || !gameState.ghostPiece || gameState.isSwapping) {
                gameState.isDragging = false;
                return;
            }
            
            const placedSuccessfully = tryPlacePiece();
            
            if (!placedSuccessfully) {
                gameState.draggedPiece.classList.remove('piece-hidden');
            }
            
            cleanupDragState();
            e.preventDefault();
        }

        // 触摸结束事件
        function handleTouchEnd(e) {
            if (!gameState.isDragging || !gameState.draggedPiece || !gameState.ghostPiece || gameState.isSwapping) {
                gameState.isDragging = false;
                return;
            }
            
            // 检查是否是点击而非拖拽
            const touch = e.changedTouches[0];
            const distanceMoved = Math.hypot(
                touch.clientX - gameState.touchStartX,
                touch.clientY - gameState.touchStartY
            );
            
            // 如果移动距离很小，视为点击而非拖拽
            if (distanceMoved < 10) {
                gameState.draggedPiece.classList.remove('piece-hidden', 'touch-active');
                cleanupDragState();
                e.preventDefault();
                return;
            }
            
            const placedSuccessfully = tryPlacePiece();
            
            if (!placedSuccessfully) {
                gameState.draggedPiece.classList.remove('piece-hidden', 'touch-active');
            }
            
            cleanupDragState();
            e.preventDefault();
        }

        // 触摸取消事件
        function handleTouchCancel() {
            if (gameState.isDragging && !gameState.isSwapping) {
                if (gameState.draggedPiece) {
                    gameState.draggedPiece.classList.remove('piece-hidden', 'touch-active');
                }
                cleanupDragState();
            }
        }

        // 处理鼠标离开窗口的情况
        function handleMouseLeave() {
            if (gameState.isDragging && !gameState.isSwapping) {
                if (gameState.draggedPiece) {
                    gameState.draggedPiece.classList.remove('piece-hidden');
                }
                cleanupDragState();
            }
        }

        // 尝试放置拼图块 - 核心验证逻辑，包含拼图交换功能
        function tryPlacePiece() {
            if (gameState.currentDropZone && !gameState.isSwapping) {
                // 获取位置索引和拼图块索引
                const positionIndex = parseInt(gameState.currentDropZone.dataset.index);
                const pieceIndex = parseInt(gameState.draggedPiece.dataset.index);
                const pieceId = gameState.draggedPiece.id;
                
                // 检查位置是否已被占用
                if (gameState.currentDropZone.firstChild) {
                    // 获取已有拼图块
                    const existingPiece = gameState.currentDropZone.firstChild;
                    
                    // 检查是否是同一个拼图块（防止自身交换）
                    if (existingPiece.id === pieceId) {
                        return false;
                    }
                    
                    // 只有错误放置的拼图块才能被交换
                    if (existingPiece.classList.contains('incorrect-piece')) {
                        // 执行交换操作 - 这算一次移动
                        incrementMoveCount();
                        return swapPieces(gameState.draggedPiece, existingPiece);
                    }
                    
                    // 正确放置的拼图块不能被交换
                    return false;
                }
                
                // 位置为空，直接放置新拼图块 - 这算一次移动
                incrementMoveCount();
                
                // 移动拼图块到目标位置
                gameState.draggedPiece.remove();
                gameState.currentDropZone.appendChild(gameState.draggedPiece);
                gameState.draggedPiece.classList.remove('cursor-grab', 'active:cursor-grabbing', 'puzzle-hover', 'piece-hidden', 'touch-active');
                
                // 验证：位置索引是否与拼图块索引匹配
                validatePiecePosition(gameState.draggedPiece, positionIndex);
                
                // 更新UI显示
                dom.moves.textContent = gameState.moves;
                dom.completed.textContent = gameState.completedPieces;
                
                // 检查游戏是否完成
                if (gameState.completedPieces === TOTAL_PIECES) {
                    completeGame();
                }
                
                return true;
            }
            
            return false;
        }

        // 增加移动计数 - 确保每次操作只计数一次
        function incrementMoveCount() {
            if (!gameState.isNewMove) {
                gameState.moves++;
                gameState.isNewMove = true;
            }
        }

        // 验证拼图块位置是否正确的通用函数
        function validatePiecePosition(pieceElement, positionIndex) {
            const pieceId = pieceElement.id;
            const pieceIndex = parseInt(pieceElement.dataset.index);
            const pieceData = gameState.pieces.find(p => p.id === pieceId);
            
            if (!pieceData) return;
            
            // 清除所有可能的边框样式
            pieceElement.classList.remove('correct-piece', 'incorrect-piece');
            
            // 关键验证：位置索引是否与拼图块索引匹配
            const isCorrect = positionIndex === pieceIndex;
            
            // 检查状态变化：是否从错误变为正确
            const stateChangedToCorrect = isCorrect && !pieceData.isCorrect;
            
            // 检查状态变化：是否从正确变为错误
            const stateChangedToIncorrect = !isCorrect && pieceData.isCorrect;
            
            if (isCorrect) {
                // 正确放置
                pieceElement.classList.add('correct-piece', 'completed-animation');
                pieceElement.removeEventListener('mousedown', handleMouseDown);
                pieceElement.removeEventListener('touchstart', handleTouchStart);
                
                // 更新游戏状态
                pieceData.placed = true;
                pieceData.isCorrect = true;
                
                // 如果是从错误变为正确，增加完成计数
                if (stateChangedToCorrect) {
                    gameState.completedPieces++;
                }
                
                gameState.pieceErrors[pieceId] = 0;
            } else {
                // 错误放置
                pieceElement.classList.add('incorrect-piece', 'puzzle-hover', 'cursor-grab', 'active:cursor-grabbing');
                
                // 更新游戏状态
                pieceData.isCorrect = false;
                
                // 如果是从正确变为错误，减少完成计数
                if (stateChangedToIncorrect) {
                    gameState.completedPieces--;
                }
                
                gameState.pieceErrors[pieceId]++;
                
                // 只更新颜色提示，不显示文字提示
                if (gameState.pieceErrors[pieceId] >= MAX_PIECE_ERRORS) {
                    highlightCorrectPosition(pieceElement);
                    gameState.pieceErrors[pieceId] = Math.floor(MAX_PIECE_ERRORS / 2);
                }
            }
        }

        // 高亮显示正确位置（仅颜色提示，无文字）
        function highlightCorrectPosition(pieceElement) {
            const correctRow = parseInt(pieceElement.dataset.correctRow);
            const correctCol = parseInt(pieceElement.dataset.correctCol);
            const correctPositionId = `position-${correctRow * COLS + correctCol}`;
            const correctPosition = document.getElementById(correctPositionId);
            
            if (correctPosition) {
                // 仅添加颜色高亮效果，不显示文字提示
                correctPosition.classList.add('hint-highlight');
                
                // 3秒后移除高亮
                setTimeout(() => {
                    if (correctPosition) {
                        correctPosition.classList.remove('hint-highlight');
                    }
                }, 3000);
            }
        }

        // 交换两个拼图块的位置 - 完善计数逻辑版
        function swapPieces(newPiece, existingPiece) {
            // 标记为正在交换中，防止重复操作
            gameState.isSwapping = true;
            
            // 1. 记录拖拽前的坐标（原始父容器）
            const originalParent = gameState.draggedPieceOriginalParent;
            
            // 2. 获取现有拼图块的信息
            const existingPieceId = existingPiece.id;
            const existingPieceIndex = existingPiece.dataset.index;
            const existingPieceCorrectRow = existingPiece.dataset.correctRow;
            const existingPieceCorrectCol = existingPiece.dataset.correctCol;
            
            // 3. 保存新拼图块的信息
            const newPieceId = newPiece.id;
            const newPieceIndex = newPiece.dataset.index;
            const newPieceCorrectRow = newPiece.dataset.correctRow;
            const newPieceCorrectCol = newPiece.dataset.correctCol;
            
            // 4. 获取目标位置和原始位置的索引
            const targetPosition = gameState.currentDropZone;
            const targetPositionIndex = parseInt(targetPosition.dataset.index);
            
            // 获取原始位置的索引（如果原始位置是拼图位置而非拼图池）
            let originalPositionIndex = null;
            if (originalParent.id && originalParent.id.startsWith('position-')) {
                originalPositionIndex = parseInt(originalParent.dataset.index);
            }
            
            // 5. 移除两个拼图块
            newPiece.remove();
            existingPiece.remove();
            
            // 6. 在原始位置生成现有拼图块的副本
            const existingPieceClone = createPieceClone(
                existingPieceId, 
                existingPieceIndex, 
                existingPieceCorrectRow, 
                existingPieceCorrectCol
            );
            originalParent.appendChild(existingPieceClone);
            
            // 7. 在目标位置生成新拼图块的副本
            const newPieceClone = createPieceClone(
                newPieceId, 
                newPieceIndex, 
                newPieceCorrectRow, 
                newPieceCorrectCol
            );
            targetPosition.appendChild(newPieceClone);
            
            // 8. 对两个拼图块都进行位置验证
            // 验证新拼图块在目标位置是否正确
            validatePiecePosition(newPieceClone, targetPositionIndex);
            
            // 验证现有拼图块在新位置（原始位置）是否正确
            if (originalPositionIndex !== null) {
                validatePiecePosition(existingPieceClone, originalPositionIndex);
            } else {
                // 如果是放在拼图池，不需要验证，但需要确保样式正确
                existingPieceClone.classList.remove('correct-piece', 'incorrect-piece');
                existingPieceClone.classList.add('puzzle-hover', 'cursor-grab', 'active:cursor-grabbing');
                
                // 如果之前是正确放置的，现在移回拼图池，需要减少完成计数
                const existingPieceData = gameState.pieces.find(p => p.id === existingPieceId);
                if (existingPieceData && existingPieceData.isCorrect) {
                    existingPieceData.isCorrect = false;
                    gameState.completedPieces--;
                }
            }
            
            // 9. 更新UI显示
            dom.moves.textContent = gameState.moves;
            dom.completed.textContent = gameState.completedPieces;
            
            // 10. 检查游戏是否完成
            if (gameState.completedPieces === TOTAL_PIECES) {
                completeGame();
            }
            
            // 11. 标记交换完成
            gameState.isSwapping = false;
            
            return true;
        }

        // 创建拼图块的副本
        function createPieceClone(id, index, correctRow, correctCol) {
            const piece = gameState.pieces.find(p => p.id === id);
            if (!piece) return null;
            
            const clone = document.createElement('div');
            clone.id = id;
            clone.className = 'puzzle-shadow puzzle-hover cursor-grab active:cursor-grabbing aspect-square rounded-md overflow-hidden';
            clone.style.width = `${piece.size}px`;
            clone.style.height = `${piece.size}px`;
            clone.style.backgroundImage = `url(${gameState.image.src})`;
            clone.style.backgroundPosition = `${piece.x}px ${piece.y}px`;
            clone.style.backgroundSize = `${piece.size * COLS}px ${piece.size * ROWS}px`;
            clone.dataset.index = index;
            clone.dataset.correctRow = correctRow;
            clone.dataset.correctCol = correctCol;
            
            // 添加事件监听
            clone.addEventListener('mousedown', handleMouseDown);
            clone.addEventListener('touchstart', handleTouchStart, { passive: false });
            
            return clone;
        }

        // 清理拖拽状态
        function cleanupDragState() {
            if (gameState.ghostPiece) {
                gameState.ghostPiece.remove();
            }
            
            if (gameState.currentDropZone) {
                gameState.currentDropZone.classList.remove('drop-highlight');
                gameState.currentDropZone = null;
            }
            
            gameState.isDragging = false;
            gameState.draggedPiece = null;
            gameState.ghostPiece = null;
            gameState.draggedPieceOriginalParent = null;
            gameState.isNewMove = false; // 重置新移动标记
        }

        // 更新当前鼠标/触摸下方的放置区域
        function updateCurrentDropZone(x, y) {
            let elements;
            try {
                elements = document.elementsFromPoint(x, y);
            } catch (e) {
                return;
            }
            
            let newDropZone = null;
            for (const el of elements) {
                if (el.id && el.id.startsWith('position-')) {
                    newDropZone = el;
                    break;
                }
            }
            
            if (newDropZone && newDropZone !== gameState.currentDropZone) {
                if (gameState.currentDropZone) {
                    gameState.currentDropZone.classList.remove('drop-highlight');
                }
                gameState.currentDropZone = newDropZone;
                gameState.currentDropZone.classList.add('drop-highlight');
            } else if (!newDropZone && gameState.currentDropZone) {
                gameState.currentDropZone.classList.remove('drop-highlight');
                gameState.currentDropZone = null;
            }
        }

        // 计时器相关函数
        function startTimer() {
            gameState.startTime = new Date();
            gameState.timerInterval = setInterval(updateTimer, 1000);
        }

        function updateTimer() {
            const now = new Date();
            gameState.elapsedTime = Math.floor((now - gameState.startTime) / 1000);
            
            const minutes = Math.floor(gameState.elapsedTime / 60).toString().padStart(2, '0');
            const seconds = (gameState.elapsedTime % 60).toString().padStart(2, '0');
            
            dom.timer.textContent = `${minutes}:${seconds}`;
        }

        // 完成游戏
        function completeGame() {
            clearInterval(gameState.timerInterval);
            
            const minutes = Math.floor(gameState.elapsedTime / 60).toString().padStart(2, '0');
            const seconds = (gameState.elapsedTime % 60).toString().padStart(2, '0');
            
            dom.finalTime.textContent = `${minutes}:${seconds}`;
            dom.finalMoves.textContent = gameState.moves;
            
            dom.completionModal.classList.remove('hidden');
        }

        // 重置游戏 - 彻底修复版
        function resetGame() {
            // 强制显示加载状态
            dom.loadingState.classList.remove('hidden');
            dom.loadingState.innerHTML = `
                <div class="flex flex-col items-center">
                    <div class="w-8 h-8 border-2 border-primary border-t-transparent rounded-full animate-spin mb-2"></div>
                    <span>重新开始游戏...</span>
                </div>
            `;
            
            // 隐藏拼图区域
            dom.puzzleContainer.classList.add('hidden');
            dom.thumbnailContainer.classList.add('hidden');
            
            // 确保图片已加载
            if (gameState.image) {
                // 重置游戏状态并重新开始
                setTimeout(() => {
                    // 强制清空拼图容器和拼图块池
                    dom.puzzleContainer.innerHTML = '';
                    dom.piecesContainer.innerHTML = '';
                    
                    // 重新初始化游戏
                    startNewGame();
                    
                    // 确保隐藏加载状态并显示拼图区域
                    dom.loadingState.classList.add('hidden');
                    dom.puzzleContainer.classList.remove('hidden');
                    dom.thumbnailContainer.classList.remove('hidden');
                }, 500);
            } else {
                // 如果图片未加载，则重新加载默认图片
                setTimeout(() => {
                    loadDefaultImage();
                }, 500);
            }
        }

        // 工具函数：打乱数组顺序
        function shuffleArray(array) {
            for (let i = array.length - 1; i > 0; i--) {
                const j = Math.floor(Math.random() * (i + 1));
                [array[i], array[j]] = [array[j], array[i]];
            }
        }

        // 初始化游戏
        function initGame() {
            initEventListeners();
            loadDefaultImage();
            
            // 监听窗口大小变化，动态调整拼图尺寸
            window.addEventListener('resize', function() {
                if (gameState.image) {
                    startNewGame();
                }
            });
        }

        // 页面加载完成后初始化游戏
        document.addEventListener('DOMContentLoaded', initGame);
    </script>
</body>
</html>